<script setup lang="ts">
import { onMounted, reactive, ref, h, computed, provide } from 'vue';
import { useMessage, NCard, NDataTable, NButton, NSpace, NModal, CascaderOption } from 'naive-ui';
import CreateProduct from "../components/CreateProduct.vue";
import UpdateProduct from "../components/UpdateProduct.vue";
import router from '../router';
import { getToken } from '../util/token';
import { defer } from '../util/decorator';
import { handleNoToken } from '../util/handler';
import statusCode from '../api/statusCode';
import { deleteProduct, findAllProduct, ProductInfo } from '../api/product';
import { Category, getCategories, queryCategoryName } from '../api/category';

const message = useMessage();

const productInfos = reactive<ProductInfo[]>([]);

const currentId = +router.currentRoute.value.params.storeId;

const handleCreateProduct = () => (showNewProduct.value = true);

const queryAllProduct = async () => {
  const token = getToken();
  if (!token) {
    handleNoToken(message);
    return [];
  }
  try {
    const resp = await findAllProduct({ storeId: currentId, token});

    if (resp.status === statusCode.SUCCESS) {
      return resp.data;
    } else if (resp.status === statusCode.QUERY_PRODUCT_FAILED) {
      // this store has no product.
      return [];
    } else {
      throw new Error(`错误码 ${resp.status}`);
    }
  } catch (error) {
    message.error("" + error);
    return [];
  }
};

const createColumns = ({
  handleOpenAttribute,
  handleUpdate,
  handleDelete
}: {
  handleOpenAttribute: (rowData: ProductInfo) => void,
  handleUpdate: (rowData: ProductInfo) => void,
  handleDelete: (rowData: ProductInfo) => void
}) => {
  return [
    {
      title: '商品名称',
      key: 'productName'
    },
    {
      title: '商品分类',
      key: 'categoryId',
      render(row: ProductInfo) {
        const id = row.categoryId;
        const name = computed(() => id in categoryIdToName ? categoryIdToName[id] : categoryIdToName[-1]);
        return h('span', name.value);
      }
    },
    {
      key: 'actions',
      render(row: ProductInfo) {
        return [
          h(
            NButton,
            {
              size: 'small',
              onClick: () => handleOpenAttribute(row)
            },
            { default: () => '管理商品SKU' }
          ),
          h(
            NButton,
            {
              size: 'small',
              onClick: () => handleUpdate(row)
            },
            { default: () => '更新商品信息' }
          ),
          h(
            NButton,
            {
              size: 'small',
              onClick: () => handleDelete(row),
              type: 'error'
            },
            { default: () => '删除商品' }
          ),
        ]
      }
    }
  ]
};

const onDelete = async (product: ProductInfo) => {
  const token = getToken();
  if (!token) {
    handleNoToken(message);
    return;
  }
  try {
    const resp = await deleteProduct({ productId: product.productId, token });

    if (resp.status === statusCode.SUCCESS) {
      message.success(`成功删除商品${product.productName}`, {
          duration: 1500,
          onAfterLeave: refreshList
      });
    } else {
      throw new Error(`错误码 ${resp.status}`);
    }
  } catch (error) {
    message.error("" + error);
  }
};

const columns = createColumns({
  handleOpenAttribute: (row) => handleOpenAttribute(row.productId),
  handleUpdate: (row) => handleUpdateProduct(row),
  handleDelete: onDelete
});

const categoryIdToName = reactive<Record<string, string>>({ '-1': '未知分类' });
const queryCategoryNames = async (ids: number[]) => {
  const itr = new Set(ids).values();
  [...itr].forEach(async (id) => {
    try {
      const resp = await queryCategoryName(id)
      if (resp.status == statusCode.SUCCESS) {
        const [id, name] = Object.entries(resp.data)[0];
        categoryIdToName[id] = name;
      }
    } catch (error) {
      message.error(`获取categoryId ${id}时发生了错误：${error}`);
    }
  });
};

const nameToCategoryId = computed(() =>
  Object.fromEntries(
    Object.entries(categoryIdToName)
      .map(([id, name]) => [name, id])
  )
);

provide('categoryIdToName', categoryIdToName);
provide('computedNameToCategoryId', nameToCategoryId);

const tableLoading = ref(true);

const createProductTable = async () => {
  tableLoading.value = true;

  try {
    const products = await queryAllProduct();
    productInfos.length = 0;
    queryCategoryNames(products.map(info => info.categoryId));
    productInfos.push(...products);
  } catch (error) {
    message.error('' + error);
  } finally {
    tableLoading.value = false;
  }
};

const refreshList = createProductTable;

const deferedCreateProductTable = defer(refreshList);

onMounted(createProductTable);


const handleOpenAttribute = (productId: number) => {
  router.push({ name: 'userStoreProduct', params: { storeId: currentId, productId }});
};

const showNewProduct = ref(false);

const tempProduct = ref<ProductInfo>({ productId: -1, productName: '', categoryId: -1, storeId: currentId, attribute: [] });
const showUpdateProduct = ref(false);
const handleUpdateProduct = (product: ProductInfo) => {
  tempProduct.value = product;
  showUpdateProduct.value = true;
};


const queryCategories = async () => {
  try {
    const resp = await getCategories();

    if (resp.status === statusCode.SUCCESS) {
      return resp.data;
    } else {
      throw new Error(`错误码：${resp.status}`);
    }
  } catch (error) {
    message.error(''+error);
    return [];
  }
};

const convertToOption = (info: Category): CascaderOption => {
  const option: CascaderOption = {
    label: info.categoryName,
    value: info.categoryId
  };

  if (info.list) option.children = info.list.map(item => convertToOption(item));

  return option;
};

const createOptions = (infos: Category[]): CascaderOption[] => {
  return infos.map(info => convertToOption(info));
};

const categoryOptions = reactive<CascaderOption[]>([]);

const setCategories = async () => {
  const categories = await queryCategories();

  const options = createOptions(categories);
  categoryOptions.length = 0;
  categoryOptions.push(...options);
};

onMounted(setCategories);
provide('categoryOptions', categoryOptions);
</script>

<template>
  <n-card title="商品列表">
    <n-space
      vertical
      size="large"
    >
      <n-space size="medium">
        <n-button
          type="primary"
          @click="handleCreateProduct"
        >
          新建商品
        </n-button>
        <n-button
          type="default"
          @click="deferedCreateProductTable"
        >
          刷新
        </n-button>
      </n-space>
      <n-data-table
        :loading="tableLoading"
        :columns="columns"
        :data="productInfos"
        :pagination="{ pageSize: 10 }"
      />
    </n-space>
  </n-card>
  
  <n-modal
    v-model:show="showNewProduct"
    :mask-closable="false"
    class="modal"
  >
    <create-product
      @close-product="showNewProduct = false"
      @refresh-list="refreshList"
    />
  </n-modal>
  <n-modal
    v-model:show="showUpdateProduct"
    :mask-closable="false"
    class="modal"
  >
    <update-product
      :product="tempProduct"
      @close-product="showUpdateProduct = false"
      @refresh-list="refreshList"
    />
  </n-modal>
</template>

<style scoped>
.modal {
  max-width: 50vw;
}
</style>
